﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Win32;
using System.Linq;
using System.IO;
using System.Text.RegularExpressions;

using MultiGed2.Provoz;
using MultiGed2.Topologie;

namespace MultiGed2
{
 /// <summary>
 /// Trida s pomocnymi funkcemi.
 /// TODO: roztridit.
 /// </summary>
 public class Utils
 {
  /// <summary>
  /// Cesta k registrum aplikace.
  /// </summary>
  private static string regPath = "Software\\MultiGed2";
  public static string regPosX = "PosX";
  public static string regPosY = "PosY";
  public static string regLastDir = "LastDir";
  public static string regLastFile = "LastFile";
  public static string regOblast = "oblIndex";

  /// <summary>
  /// Precte hodnotu z registru.
  /// </summary>
  /// <param name="valName">Nazev hodnoty.</param>
  /// <returns>Objekt obsahujici hodnotu.</returns>
  public static object ReadRegistryValue(string valName)
  {
   object r = null;
   RegistryKey rk = Registry.CurrentUser.OpenSubKey(regPath);
   if (rk != null)
   {
    object v = rk.GetValue(valName);
    if (v != null)
    {
     RegistryValueKind rvk = rk.GetValueKind(valName);
     switch (rvk)
     {
      case RegistryValueKind.DWord:
       r = Convert.ToInt32(v);
       break;
      default:
       r = v;
       break;
     }
    }
    rk.Close();
   }
   return r;
  }

  /// <summary>
  /// Zapise hodnotu do registru. Vytvori aplikacni registr, pokud neexistuje.
  /// </summary>
  /// <param name="valName">Nazev hodnoty.</param>
  /// <param name="val">Obsah hodnoty.</param>
  /// <returns>Pravda, pokud se povedlo.</returns>
  public static bool WriteRegistryValue(string valName, object val)
  {
   bool r = false;
   RegistryKey rk = Registry.CurrentUser.CreateSubKey(regPath);
   if (rk != null)
   {
    rk.SetValue(valName, val);
    rk.Close();
    r = true;
   }
   return r;
  }

  /// <summary>
  /// Prevede kategorii vlaku jako retezec na vyctovy typ kategorie a druh jizdnich dob.
  /// </summary>
  /// <param name="sKategorieVlaku">Kategorie vlaku jako text.</param>
  /// <param name="eKategorie">Vystupni promenna pro kategorii vlaku.</param>
  /// <param name="eDruhJd">Vystupni promenna pro druh jizdnich dob vlaku.</param>
  /// <returns>Pravda pri uspesnem prirazeni.</returns>
  public static bool vlakDruh(string sKategorieVlaku, out KategorieVlaku eKategorie, out VlDruhJD eDruhJd)
  {
   string kategorie = sKategorieVlaku.Trim().ToUpper();
   eDruhJd = VlDruhJD.Nakl;
   eKategorie = KategorieVlaku.Pn;
   bool r = true;
   if (kategorie == "EN")
    eKategorie = KategorieVlaku.EN;
   else if (kategorie == "EC")
    eKategorie = KategorieVlaku.EC;
   else if (kategorie == "IC")
    eKategorie = KategorieVlaku.IC;
   else if (kategorie == "EX")
    eKategorie = KategorieVlaku.Ex;
   else if (kategorie == "R")
    eKategorie = KategorieVlaku.R;
   else if (kategorie == "SP")
    eKategorie = KategorieVlaku.Sp;
   else if (kategorie == "OS")
    eKategorie = KategorieVlaku.Os;
   else if (kategorie == "SV")
    eKategorie = KategorieVlaku.Sv;
   else if (kategorie == "OS Z")
    eKategorie = KategorieVlaku.Osz;
   else if (kategorie == "NEX")
    eKategorie = KategorieVlaku.Nex;
   else if (kategorie == "RN")
    eKategorie = KategorieVlaku.Rn;
   else if (kategorie == "VN")
    eKategorie = KategorieVlaku.Vn;
   else if (kategorie == "PN")
    eKategorie = KategorieVlaku.Pn;
   else if (kategorie == "MN")
    eKategorie = KategorieVlaku.Mn;
   else if (kategorie == "PV")
    eKategorie = KategorieVlaku.Pv;
   else if (kategorie == "LV")
    eKategorie = KategorieVlaku.Lv;
   else if (kategorie == "MEN")
    eKategorie = KategorieVlaku.MEN;
   else if (kategorie == "MEC")
    eKategorie = KategorieVlaku.MEC;
   else if (kategorie == "MIC")
    eKategorie = KategorieVlaku.MIC;
   else if (kategorie == "MEX")
    eKategorie = KategorieVlaku.MEx;
   else if (kategorie == "MR")
    eKategorie = KategorieVlaku.MR;
   else if (kategorie == "MSP")
    eKategorie = KategorieVlaku.MSp;
   else if (kategorie == "MOS")
    eKategorie = KategorieVlaku.MOs;
   else if (kategorie == "MSV")
    eKategorie = KategorieVlaku.MSv;
   else if (kategorie == "MOSZ")
    eKategorie = KategorieVlaku.MOsz;
   else
    r = false;

   if (r)
   {
    switch (eKategorie)
    {
     case KategorieVlaku.EN:
     case KategorieVlaku.MEN:
     case KategorieVlaku.EC:
     case KategorieVlaku.MEC:
     case KategorieVlaku.IC:
     case KategorieVlaku.MIC:
     case KategorieVlaku.Ex:
     case KategorieVlaku.MEx:
     case KategorieVlaku.R:
     case KategorieVlaku.MR:
     case KategorieVlaku.Sp:
     case KategorieVlaku.MSp:
     case KategorieVlaku.Os:
     case KategorieVlaku.MOs:
     case KategorieVlaku.Sv:
     case KategorieVlaku.MSv:
      eDruhJd = VlDruhJD.R;
      break;
     case KategorieVlaku.Osz:
     case KategorieVlaku.MOsz:
      eDruhJd = VlDruhJD.Os;
      break;
     case KategorieVlaku.Nex:
     case KategorieVlaku.Rn:
     case KategorieVlaku.Vn:
     case KategorieVlaku.Pn:
     case KategorieVlaku.Mn:
     case KategorieVlaku.Pv:
      eDruhJd = VlDruhJD.Nakl;
      break;
     case KategorieVlaku.Lv:
      eDruhJd = VlDruhJD.Lv;
      break;
    }
   }
   return r;
  }

  /// <summary>
  /// Prevede omezeni jizdy jako znak na vyctovy typ pro omezeni.
  /// </summary>
  /// <param name="kod">Znak omezeni.</param>
  /// <param name="omezeni">Vystupni promenna pro vyctovy typ.</param>
  /// <returns>Pravda, pri uspesnem prirazeni.</returns>
  public static bool omezeniJizdy(char kod, out OmezeniJizdy omezeni)
  {
   bool r = true;
   omezeni = OmezeniJizdy.Denne;
   if (kod == '\0')
    omezeni = OmezeniJizdy.Denne;
   else if (kod == '1')
    omezeni = OmezeniJizdy.Jede1;
   else if (kod == '2')
    omezeni = OmezeniJizdy.Jede2;
   else if (kod == '3')
    omezeni = OmezeniJizdy.Jede3;
   else if (kod == '4')
    omezeni = OmezeniJizdy.Jede4;
   else if (kod == '5')
    omezeni = OmezeniJizdy.Jede5;
   else if (kod == '6')
    omezeni = OmezeniJizdy.Jede6;
   else if (kod == '7')
    omezeni = OmezeniJizdy.Jede7;
   else if (kod == '8')
    omezeni = OmezeniJizdy.PracDny;
   else if (kod == '9')
    omezeni = OmezeniJizdy.Vikendy;
   else if (kod == 'A')
    omezeni = OmezeniJizdy.MimoNedele;
   else if (kod == 'B')
    omezeni = OmezeniJizdy.MimoSoboty;
   else if (kod == 'C')
    omezeni = OmezeniJizdy.PoStPa;
   else if (kod == 'D')
    omezeni = OmezeniJizdy.UtCtSo;
   else if (kod == 'P')
    omezeni = OmezeniJizdy.PodlePotreby;
   else
    r = false;
   return r;
  }

  /// <summary>
  /// Prevede mimoradnost jako znak na vyctovy typ pro mimoradnost,
  /// pripadne i dopravnu.
  /// </summary>
  /// <param name="kod">Kod mimoradnosti.</param>
  /// <param name="oblast">Oblast, ve ktere se bude hledat pripadna dopravna.</param>
  /// <param name="eMimoradnost">Vyctovy typ mimoradnosti.</param>
  /// <param name="dopravna">Pripadna dopravna, ke ktere mimoradnost prislusi.</param>
  /// <returns>Pravda pri uspesnem prirazeni.</returns>
  public static bool mimoradnost(char kod,
   Oblast oblast,
   out MimoradnostVlaku eMimoradnost,
   out Dopravna dopravna)
  {
   bool r = true;
   eMimoradnost = MimoradnostVlaku.Zadna;
   dopravna = null;
   if (kod == '\0')
    r = true;
   else if (kod == '1')
    eMimoradnost = MimoradnostVlaku.JedeSPostrkem;
   else if (kod >= 'a' && kod <= 'z')
   {
    eMimoradnost = MimoradnostVlaku.NTP;
    dopravna = dopravnaPodleKodu(oblast, Char.ToUpper(kod));
    if (dopravna == null)
     r = false;
   }
   else if (kod >= 'A' && kod <= 'Z')
   {
    eMimoradnost = MimoradnostVlaku.Postrk;
    dopravna = dopravnaPodleKodu(oblast, kod);
    if (dopravna == null)
     r = false;
   }
   else if (kod == '?')
    eMimoradnost = MimoradnostVlaku.NahodnyPostrk;
   else if (kod == '!')
    eMimoradnost = MimoradnostVlaku.Mimoza;
   else if (kod == '#')
    eMimoradnost = MimoradnostVlaku.Pendular;
   else
    r = false;
   return r;
  }

  /// <summary>
  /// Vraci znak, pokud je tisknutelny.
  /// </summary>
  /// <param name="c">Znak pro prevod.</param>
  /// <returns>Znak nebo 0 pokud je netisknutelny.</returns>
  public static char wc2z(char c)
  {
   return c == ' ' || c == '\t' ? '\0' : c;
  }

  /// <summary>
  /// 
  /// </summary>
  /// <param name="smer"></param>
  /// <returns></returns>
  public static SmerJizdy smerJizdy(char smer)
  {
   SmerJizdy r = SmerJizdy.Nedefinovany;
   if (smer == 'S')
    r = SmerJizdy.Sudy;
   else if (smer == 'L')
    r = SmerJizdy.Lichy;
   return r;
  }

  /// <summary>
  /// Prevede znak na bool.
  /// </summary>
  /// <param name="c">Znak pro prevod.</param>
  /// <returns>Pravda, pokud je na vstupu 'T'.</returns>
  public static bool TF(char c)
  {
   return c == 'T' ? true : false;
  }

  /// <summary>
  /// Kontrola casu.
  /// </summary>
  /// <param name="h">Hodiny.</param>
  /// <param name="m">Minuty.</param>
  /// <returns>Pravda, pokud je cas 00:00 - 23:59</returns>
  public static bool hodminOK(byte h, byte m)
  {
   return h >= 0 && h < 24 && m >= 0 && m < 60;
  }

  /// <summary>
  /// Kontrola nahodneho casu.
  /// </summary>
  /// <param name="h">Hodiny.</param>
  /// <param name="m">Minuty.</param>
  /// <returns>Pravda, pokud je cas nahodny.</returns>
  public static bool casNah(byte h, byte m)
  {
   return h == 99 && m == 99;
  }

  /// <summary>
  /// Prevod retezce na cislo.
  /// </summary>
  /// <param name="s">Cislo jako text.</param>
  /// <returns>Prevedene cislo nebo 0.</returns>
  public static uint strToCisloOr0(string s)
  {
   uint r = 0;
   try
   {
    r = UInt32.Parse(s);
   }
   catch (FormatException)
   {
   }
   return r;
  }

  /// <summary>
  /// Zjisti, zda dana oblast obsahuje dopravnu.
  /// </summary>
  /// <param name="o">Oblast.</param>
  /// <param name="kod">Kod dopravny.</param>
  /// <returns>Pravda, pokud obsahuje.</returns>
  private static bool checkKodDopravnyOblasti(Oblast o, char kod)
  {
   return o.dopravny.Where(
    d => d.kod == kod)
    .Count() > 0;
  }

  /// <summary>
  /// Najdi dopravnu podle kodu.
  /// </summary>
  /// <param name="o">Oblast.</param>
  /// <param name="kod">Kod dopravny.</param>
  /// <returns>Nalezena dopravna nebo null.</returns>
  public static Dopravna dopravnaPodleKodu(Oblast o, char kod)
  {
   var iter = o.dopravny.Where(
    d => d.kod == kod);
   if(iter.Count() == 0)
    return null;
   if(iter.Count() == 1)
    return iter.ElementAt(0);
   return iter.Where(
    d => d.kategorie != KategorieDopravny.Pomocna)
    .First();
  }

  /// <summary>
  /// Zjisti, zda je dany kod dopravny v oblasti spravny
  /// pro oznaceni dopravny na pozici pro obrat/mimoradnost.
  /// </summary>
  /// <param name="o">Oblast.</param>
  /// <param name="kod">Kod dopravny.</param>
  /// <returns>Pravda, pokud je kod spravny.</returns>
  private static bool checkKodStanMimoradnosObrat(Oblast o, char kod)
  {
   bool r = false;
   if (kod == '\0')
   {
    r = true;
   }
   else if (kod == '?' || kod == '!' || kod == '#')
   {
    r = true; //???
   }
   else
   {
    r = o.dopravny.Where(
     d => d.kod == kod && d.kategorie == KategorieDopravny.Zst)
     .Count() > 0;
   }
   return r;
  }

  //public static bool CheckStaniceVlak(Oblast o, Vlak v)
  //{
  // bool r = true;
  // if (!(checkKodDopravnyOblasti(o, v.dopravnaVych) &&
  //  checkKodDopravnyOblasti(o, v.dopravnaCil) &&
  //  checkKodDopravnyOblasti(o, v.kodStanObratLv) &&
  //  checkKodDopravnyOblasti(o, v.kodStanZvnitr) &&
  //  checkKodStanMimoradnosObrat(o, v.dopravnaOper) &&
  //  checkKodStanMimoradnosObrat(o, v.mimoradnost)))
  //  r = false;
  // return r;
  //}

  //public static short kontrolaStanicVlaku(Oblast o, List<Vlak> vlaky)
  //{
  // short r = 0;
  // foreach (Vlak v in vlaky)
  // {
  //  if (!CheckStaniceVlak(o, v))
  //  {
  //   v.stav = StavVlaku.NOK;
  //   r++;
  //  }
  // }
  // return r;
  //}

  //static bool vlakNOK(Vlak v)
  //{
  // return v.stav == StavVlaku.NOK;
  //}

  //public static void SmazatNOKvlaky(List<Vlak> vlaky)
  //{
  // vlaky.RemoveAll(new Predicate<Vlak>(vlakNOK));
  //}

  private static byte ms2kmh(byte vMs)
  {
   return (byte)(Math.Round(vMs * .36) * 10);
  }

  private static byte kmh2ms(byte vKmh)
  {
   return (byte)(vKmh / 3.6);
  }

  private static byte ms2kmh(string sMs)
  {
   return ms2kmh(Convert.ToByte(sMs));
  }

  private static byte kmh2ms(string sKmh)
  {
   return kmh2ms(Convert.ToByte(sKmh));
  }

  /// <summary>
  /// Prevede rychlost
  /// </summary>
  /// <param name="sRychlost"></param>
  /// <param name="eRychlost"></param>
  /// <returns></returns>
  public static bool rychlost(string sRychlost, out Rychlost eRychlost)
  {
   bool r = true;
   eRychlost = Rychlost.V80;
   byte kmh = ms2kmh(sRychlost);
   switch (kmh)
   {
    case 30:
     eRychlost = Rychlost.V30;
     break;
    case 40:
     eRychlost = Rychlost.V40;
     break;
    case 50:
     eRychlost = Rychlost.V50;
     break;
    case 60:
     eRychlost = Rychlost.V60;
     break;
    case 70:
     eRychlost = Rychlost.V70;
     break;
    case 80:
     eRychlost = Rychlost.V80;
     break;
    case 90:
     eRychlost = Rychlost.V90;
     break;
    case 100:
     eRychlost = Rychlost.V100;
     break;
    case 110:
     eRychlost = Rychlost.V110;
     break;
    case 120:
     eRychlost = Rychlost.V120;
     break;
    case 130:
     eRychlost = Rychlost.V130;
     break;
    case 140:
     eRychlost = Rychlost.V140;
     break;
    case 150:
     eRychlost = Rychlost.V150;
     break;
    case 160:
     eRychlost = Rychlost.V160;
     break;
    default:
     r = false;
     break;
   }
   return r;
  }

  private static string CISLO_VLAKU = @"([\s0-9]{5})";
  private static string REZERVA = @"\s";
  private static string HOD_MIN = @"([0-9]{2})([0-9]{2})";
  private static string DRUH_VLAKU = @"([\w\s]{4})";
  private static string KOD_STANICE = @"([\sA-Z])";
  private static string OMEZENI_JIZDY = @"([\s1-9ABCDP])";
  private static string RYCHLOST = @"([\s\d]{2})";
  private static string MIMORADNOST = @"([?!#\sA-Za-z])";
  private static string SMER = @"([SL])";
  private static string DELKA_VLAKU = @"([\s0-9]{2})";
  private static string NASTUPISTE = @"([TF])";
  private static string OBRAT_LOKO = @"([\s\d+]{5}|\s{4}[A-Z]|OPER\.)";
  private static string NOVY_SMER = @"([\sSL])";
  private static string STRID_OSA = @"([\so])";
  private static string OBRAT_SOUPR = @"([\s\d+]{5}|POSUN)";
  private static string JIZDNI_RAD = @"(([A-Z]\d{4})+)";

  private static string vlakVzor = "^x" + CISLO_VLAKU + REZERVA + HOD_MIN + REZERVA + DRUH_VLAKU +
   KOD_STANICE + KOD_STANICE + KOD_STANICE + OMEZENI_JIZDY + RYCHLOST + MIMORADNOST + SMER +
   REZERVA + DELKA_VLAKU + REZERVA + "T" + REZERVA + NASTUPISTE + OBRAT_LOKO + KOD_STANICE +
   NOVY_SMER + STRID_OSA + OBRAT_SOUPR + JIZDNI_RAD + @"\s*x\s*";

  /// <summary>
  /// Regularni vyraz pro rozlozeni radku vlaku.
  /// </summary>
  public static Regex vlakRE = new Regex(vlakVzor);

  /// <summary>
  /// Porovna jizdni rad a trasu na odpovidaji kody stanic.
  /// Jizni rad muze byt kratsi.
  /// </summary>
  /// <param name="jr">Jizdni rad.</param>
  /// <param name="trasa">Trasa.</param>
  /// <param name="start">Zacatek porovnavani v jizdnim radu.</param>
  /// <returns>True, pokud jsou JR podmnozinou trasy.</returns>
  private static bool porovnatJizdniRadTrasa(List<KrokJR> jr, List<Dopravna> trasa, int start)
  {
   foreach(KrokJR k in jr)
   {
    if (trasa.Count <= start || k.dopravna != trasa[start])
     return false;
    start += 1;
   }
   return true;
  }

  /// <summary>
  /// Porovna jizdni rad a trasy na odpovidaji kody stanic.
  /// Jizdni rad muze byt kratsi.
  /// </summary>
  /// <param name="jr">Jizdni rad.</param>
  /// <param name="trasy">Trasy.</param>
  /// <param name="start">Zacatek porovnavani v jizdnim radu.</param>
  /// <returns>True, pokud je JR podmnozinou nejake trasy.</returns>
  private static bool porovnatJizdniRadTrasy(List<KrokJR> jr, List<List<Dopravna>> trasy, int start)
  {
   foreach (List<Dopravna> trasa in trasy)
   {
    if (porovnatJizdniRadTrasa(jr, trasa, start))
     return true;
   }
   return false;
  }

  /// <summary>
  /// Delegat pro volani z nacitani vlaku.
  /// </summary>
  /// <param name="v">Vlak, ke kteremu se problem vztahuje.</param>
  /// <param name="s">Stav nacitani.</param>
  public delegate void LoadFeedback(Vlak v, StavNacitani s);

  /// <summary>
  /// Nacte vlaky ze souboru pro zadanou oblast.
  /// </summary>
  /// <param name="soubor">Cela cesta k vstupnimu souboru.</param>
  /// <param name="oblast">Oblast, pro kterou se nacitaji vlaky.</param>
  /// <param name="funkce">Callback funkce pro hlaseni zahozenych vlaku.</param>
  /// <param name="spatnych">Vystupni promenna pro pocet "zahozenych" radku vstupniho souboru.</param>
  /// <returns>Seznam uspesne nactenych vlaku.</returns>
  public static List<Vlak> vlakyZeSouboru(string soubor, Oblast oblast,
   LoadFeedback funkce, out short spatnych)
  {
   spatnych = 0;
   string[] radky;
   List<Vlak> vysledek = new List<Vlak>();

   radky = File.ReadAllLines(soubor);

   foreach (string r in radky)
   {
    Vlak vlak = new Vlak();
    StavNacitani stav = vlak.vlakFromString(r, oblast);
    if (stav == StavNacitani.OK)
     vysledek.Add(vlak);
    else
    {
     if (funkce != null) funkce(vlak, stav);
     spatnych++;
    }
   }

   return vysledek;
  }

  internal static void nastavTrasovaniVlaku(Vlak v)
  {
   v.trasovani = TrasovaniVlaku.Nezname;
   // vyplnena jen vychozi a cilova dopravna
   if (v.dopravnaVych != null && v.dopravnaOper == null)
    v.trasovani = TrasovaniVlaku.Z_Do;
   else if (v.dopravnaVych != null && v.dopravnaOper != null)
    v.trasovani = TrasovaniVlaku.Z_Pres_Do;
   else if (v.dopravnaVych == null && v.dopravnaOper == null)
    v.trasovani = TrasovaniVlaku.Zvnitrku;
   else if (v.dopravnaVych == null && v.dopravnaOper != null)
    v.trasovani = TrasovaniVlaku.ZvnitrkuSObtatem;
  }

  /// <summary>
  /// 
  /// </summary>
  /// <param name="v"></param>
  /// <param name="s"></param>
  public delegate void CheckFeedback(Vlak v, ChybaKontrolyDat ch);

  /// <summary>
  /// Smaze ze seznamu vlaku takove, ktere maji spatne
  /// trasovani vlaku nebo spatne sestaveny
  /// jizdni rad ve vztahu k trasovani vlaku.
  /// </summary>
  /// <param name="vlaky">Seznam vlaku ke kontrole.</param>
  /// <param name="oblast">Oblast, ke ktere se GVD vztahuje.</param>
  /// <param name="funkce">Callback funkce pro hlaseni zahozenych vlaku.</param>
  /// <param name="spatnych">Vystupni parametr, pocet zahozenych vlaku.</param>
  /// <returns>Vraci predany seznam 'vlaky', bez vlaku, ktere neprosly kontrolou. </returns>
  public static void kontrolaDatGVD(List<Vlak> vlaky, Oblast oblast,
   CheckFeedback funkce, out short spatnych)
  {
   List<List<Dopravna>> trasy = null;
   spatnych = 0;
   List<Vlak> naSmazani = null;

   foreach(Vlak v in vlaky) nastavTrasovaniVlaku(v);

   var spatneTrasovaniJR = vlaky.Where(v =>
    {
     if (v.trasovani == TrasovaniVlaku.Nezname)
     {
      if (funkce != null)
       funkce(v, ChybaKontrolyDat.Trasovani);
      return true;
     }
     else if (v.trasovani == TrasovaniVlaku.Z_Do)
     // kontrola vlaku Z-Do
     {
      trasy = Hledani.TrasaZDo(v.dopravnaVych, v.dopravnaCil, oblast);
      if (trasy.Count > 0 && porovnatJizdniRadTrasy(v.jizdniRad, trasy, 1))
       return false; // vlak zkontrolovany OK
      else
      {
       if (funkce != null)
        funkce(v, ChybaKontrolyDat.JrZDo);
       return true;
      }
     }
     else if (v.trasovani == TrasovaniVlaku.Z_Pres_Do)
     // kontrola vlaku Z-Pres-Do
     {
      trasy = Hledani.TrasaZDo2(v.dopravnaVych, v.dopravnaOper, v.dopravnaCil, oblast);
      if (trasy.Count > 0 && porovnatJizdniRadTrasy(v.jizdniRad, trasy, 1))
       return false; // vlak zkontrolovany OK
      else
      {
       if (funkce != null)
        funkce(v, ChybaKontrolyDat.JrZPresDo);
       return true;
      }
     }
     else if (v.trasovani == TrasovaniVlaku.ZvnitrkuSObtatem)
     // kontrola vlaku obracejicich uvnitr oblasti
     {
      var predchVlak = vlaky.Where(pv => pv.cisloObrSoup == v.cisloVlaku);
      if (predchVlak.Count() == 1)
      {
       Vlak vlakOd = predchVlak.First();
       trasy = Hledani.TrasaZDo(vlakOd.dopravnaOper, v.dopravnaOper, oblast);
       if (trasy.Count > 0 && porovnatJizdniRadTrasy(v.jizdniRad, trasy, 0))
        return false;
      }
      else
      {
       if (funkce != null)
        funkce(v, ChybaKontrolyDat.JrObratZvnitrku);
       return true;
      }
     }
     else if (v.trasovani == TrasovaniVlaku.Zvnitrku)
     {
      //if (v.jizdniRad.Count > 1) /*&& v.jizdniRad[0].jdDo == 0 && v.jizdniRad[0].pobyt == 0*/
      var predchVlak = vlaky.Where(pv => pv.cisloObrSoup == v.cisloVlaku);
      if(predchVlak.Count() == 0)
       // zkusit obrat loko
       predchVlak = vlaky.Where(pv => pv.cisloObrLoko == v.cisloVlaku);
      if (predchVlak.Count() == 1)
      {
       Vlak vlakOd = predchVlak.First();
       trasy = Hledani.TrasaZDo(vlakOd.dopravnaOper, v.dopravnaCil, oblast);
       if (trasy.Count > 0 && porovnatJizdniRadTrasy(v.jizdniRad, trasy, 0))
        return false; // vlak zkontrolovany OK
      }
      else
      {
       if (funkce != null)
        funkce(v, ChybaKontrolyDat.JrZvnitrku);
       return true;
      }
     }
     return true;
    });

   naSmazani = spatneTrasovaniJR.ToList();
   spatnych += (short)naSmazani.Count;
   foreach (Vlak v in naSmazani)
   {
    vlaky.Remove(v);
   }
  }
 }
}
